<template>
  <div class="testCabinet">
    <canvas class="renderCanvas" ref="renderCanvas"></canvas>
  </div>
</template>
<script>
/**
 * 机柜3D渲染组件 (Babylon.js 实现)
 * 特性：
 * 1. 机柜高度根据checkList中的maxUbit属性动态计算，支持显示47U及更高U位的机柜
 * 2. 服务器位置根据startUbit属性计算，保证正确放置在机柜内部
 * 3. 根据机柜高度动态调整摄像机位置和角度，确保完整展示整个机柜
 * 4. 优化的PBR材质和高效渲染，提供更真实的视觉效果
 * 5. 使用实例化渲染提高性能
 * 6. 智能资源管理，减少内存占用
 */
import * as BABYLON from 'babylonjs'
import 'babylonjs-loaders'
import gsap from 'gsap'
import { throttle } from 'lodash'

export default {
  name: 'testCabinet',
  inject: ['getServerCode'],
  props: {
    imgList: {
      type: Array,
      default: () => []
    },
    checkList: {
      type: Array,
      default: () => []
    },
    assetList: {
      type: Array,
      default: () => []
    }
  },
  data() {
    return {
      engine: null,
      scene: null,
      camera: null,
      cameraInfo: {},
      light: null,
      rackList: [], // 机柜模型数组
      cabinetMeshes: {}, // 机柜网格对象
      serverMeshes: {}, // 服务器网格对象
      highlightLayer: null, // 高亮层
      materialCache: {}, // 材质缓存
      textureCache: {}, // 纹理缓存
      serverRegistry: {}, // 服务器注册表
      currentOpenServerId: null, // 当前打开的服务器ID
      cabinetMaxUbit: 42, // 默认机柜高度为42U
      animating: false, // 动画标志
      defaultMaterial: null, // 默认材质
      defaultServerMaterial: null // 默认服务器材质
    }
  },
  async mounted() {
    // 确保检查列表存在并获取maxUbit
    if (this.checkList && this.checkList.length > 0 && this.checkList[0].maxUbit) {
      this.cabinetMaxUbit = parseInt(this.checkList[0].maxUbit)
    }

    await this.initBabylon()
    await this.createScene()

    // 创建机柜
    await this.createCabinet(0, 0, '')

    // 确保检查列表和资产列表存在
    if (!this.checkList || !this.checkList[0] || !this.checkList[0].devices) {
      console.error('缺少机柜设备数据')
      return
    }

    let devices = this.checkList[0].devices || []

    // 确保资产列表存在再进行过滤
    if (this.assetList && this.assetList.length > 0) {
      // 过滤掉不是IT设备
      devices = devices.filter(item => {
        return this.assetList.some(asset => asset.id == item.id && asset.isIT && asset.isGrounding)
      })
    }
    // 批量渲染设备
    await this.renderDevices(devices)

    // 注册事件处理器
    this.registerEventHandlers()
  },
  methods: {
    // 初始化Babylon引擎
    async initBabylon() {
      // 获取画布元素
      const canvas = this.$refs.renderCanvas

      // 创建Babylon引擎
      this.engine = new BABYLON.Engine(canvas, true, {
        preserveDrawingBuffer: true,
        stencil: true,
        antialias: true
      })

      // 创建不同的时间线管理不同的动画
      this.timelines = {
        frontDoor: gsap.timeline({
          onStart: () => { this.animating = true },
          onComplete: () => { this.animating = false }
        }),
        backDoor: gsap.timeline({
          onStart: () => { this.animating = true },
          onComplete: () => { this.animating = false }
        }),
        server: gsap.timeline({
          onStart: () => { this.animating = true },
          onComplete: () => { this.animating = false }
        })
      };

      // 自适应调整大小
      window.addEventListener('resize', () => {
        this.engine.resize()
      })

      // 配置引擎设置以提高性能
      this.engine.setHardwareScalingLevel(1.0) // 可根据设备性能调整

      return Promise.resolve()
    },

    // 创建场景
    async createScene() {
      // 创建场景
      this.scene = new BABYLON.Scene(this.engine)

      // 设置背景颜色 (浅蓝色)
      this.scene.clearColor = new BABYLON.Color4(0.9, 0.97, 1.0, 1.0)

      // 启用抗锯齿
      this.scene.antialiasing = true

      // 创建摄像机
      await this.createCamera()

      // 创建光源
      await this.createLights()

      // 创建高亮层
      this.highlightLayer = new BABYLON.HighlightLayer("highlightLayer", this.scene)
      this.highlightLayer.innerGlow = false
      this.highlightLayer.outerGlow = true

      // 创建默认材质
      this.defaultMaterial = this.createDefaultMaterial()
      this.defaultServerMaterial = this.createMatteBlackMaterial()

      // 开始渲染循环
      this.engine.runRenderLoop(() => {
        if (this.scene) {
          this.scene.render()
        }
      })

      return Promise.resolve()
    },

    // 创建相机
    async createCamera() {
      // 计算机柜高度
      const cabHeight = this.cabinetMaxUbit * 2 / 2

      // 创建弧形旋转相机
      this.camera = new BABYLON.ArcRotateCamera(
        "Camera",
        -Math.PI / 2, // alpha - 水平旋转
        Math.PI / 3,  // beta - 垂直旋转
        120 + this.cabinetMaxUbit, // radius - 距离
        new BABYLON.Vector3(0, cabHeight, 0), // 目标点
        this.scene
      )

      // 配置相机行为
      this.camera.attachControl(this.$refs.renderCanvas, true)
      this.camera.lowerRadiusLimit = 50
      this.camera.upperRadiusLimit = 200
      this.camera.wheelDeltaPercentage = 0.01
      this.camera.lowerBetaLimit = Math.PI / 4
      this.camera.upperBetaLimit = Math.PI / 2
      this.camera.panningSensibility = 100
      this.camera.inertia = 0.8

      // 相机视野设置
      this.camera.minZ = 0.1
      this.camera.maxZ = 1000
      this.camera.fov = 0.8

      // 记录相机初始位置信息
      this.updateCameraInfo()

      // 相机移动时更新信息
      this.camera.onViewMatrixChangedObservable.add(() => {
        this.updateCameraInfo()
      })

      return Promise.resolve()
    },

    // 更新相机信息
    updateCameraInfo() {
      this.cameraInfo = {
        x: this.camera.position.x.toFixed(2),
        y: this.camera.position.y.toFixed(2),
        z: this.camera.position.z.toFixed(2),
        targetX: this.camera.target.x.toFixed(2),
        targetY: this.camera.target.y.toFixed(2),
        targetZ: this.camera.target.z.toFixed(2)
      }
    },

    // 创建光源
    async createLights() {
      // 创建环境光
      const ambientLight = new BABYLON.HemisphericLight(
        "ambientLight",
        new BABYLON.Vector3(0, 1, 0),
        this.scene
      )
      ambientLight.intensity = 0.5
      ambientLight.diffuse = new BABYLON.Color3(1, 1, 1)
      ambientLight.specular = new BABYLON.Color3(0.25, 0.25, 0.25)
      ambientLight.groundColor = new BABYLON.Color3(0.2, 0.2, 0.5)

      // 创建主光源 (定向光)
      const mainLight = new BABYLON.DirectionalLight(
        "mainLight",
        new BABYLON.Vector3(1, -1, 1),
        this.scene
      )
      mainLight.position = new BABYLON.Vector3(-80, 100, -80)
      mainLight.intensity = 0.8
      mainLight.diffuse = new BABYLON.Color3(0.95, 0.95, 1.0)
      mainLight.specular = new BABYLON.Color3(0.7, 0.7, 0.8)

      // 添加补光，增强立体感
      const fillLight = new BABYLON.DirectionalLight(
        "fillLight",
        new BABYLON.Vector3(-0.5, -0.5, -0.5),
        this.scene
      )
      fillLight.position = new BABYLON.Vector3(50, 50, 100)
      fillLight.intensity = 0.3
      fillLight.diffuse = new BABYLON.Color3(0.8, 0.8, 0.95)

      // 保存主光源引用
      this.light = mainLight

      return Promise.resolve()
    },

    // 创建默认材质
    createDefaultMaterial() {
      // 使用PBR材质以提供更好的视觉效果
      const material = new BABYLON.PBRMaterial("defaultMaterial", this.scene)
      material.albedoColor = new BABYLON.Color3(0.22, 0.22, 0.22)
      material.metallic = 0.4
      material.roughness = 0.8
      material.microSurface = 0.8
      material.directIntensity = 0.5
      material.environmentIntensity = 0.5
      return material
    },

    // 创建磨砂黑材质
    createMatteBlackMaterial() {
      const material = new BABYLON.PBRMaterial("matteBlackMaterial", this.scene)
      material.albedoColor = new BABYLON.Color3(0.22, 0.22, 0.24) // 深灰色
      material.metallic = 0.1
      material.roughness = 0.95
      material.microSurface = 0.3
      material.directIntensity = 0.3
      material.environmentIntensity = 0.3
      // 添加噪点纹理
      const noiseTexture = this.createNoiseTexture()
      material.bumpTexture = noiseTexture
      material.bumpTexture.level = 0.05
      //设置材质不受到光照影响
      material.useLightmapAsShadowmap = false

      return material
    },

    // 创建噪点纹理
    createNoiseTexture() {
      const size = 256
      const noiseTexture = new BABYLON.DynamicTexture("noiseTexture", size, this.scene, true)
      const ctx = noiseTexture.getContext()
      ctx.fillStyle = "#121212"
      ctx.fillRect(0, 0, size, size)
      for (let i = 0; i < size; i++) {
        for (let j = 0; j < size; j++) {
          if (Math.random() > 0.75) {
            const shade = 20 + Math.floor(Math.random() * 20)
            ctx.fillStyle = `rgb(${shade},${shade},${shade})`
            ctx.fillRect(i, j, 1, 1)
          }
        }
      }

      noiseTexture.update()
      return noiseTexture
    },
    // 改进U位刻度纹理，使用动态计算的高度而非固定高度
    createUPositionTexture(side) {
      // 根据U数动态计算纹理高度，保证精确映射
      const width = 200;
      const pixelsPerU = 48; // 每个U位占用的像素高度
      const height = this.cabinetMaxUbit * pixelsPerU; // 根据机柜U数动态计算纹理高度

      const texture = new BABYLON.DynamicTexture("uPositionTexture" + side, {
        width: width,
        height: height
      }, this.scene, true);

      const ctx = texture.getContext();

      // 使用更深色的背景以增强对比度
      ctx.fillStyle = "#1a1a1a";
      ctx.fillRect(0, 0, width, height);

      const uHeight = height / this.cabinetMaxUbit; // 每个U位在纹理上占用的高度

      // 字体大小和加粗，保证清晰
      const fontSize = Math.max(Math.min(uHeight * 0.6, 44), 22);
      const fontFamily = "bold " + fontSize + "px 'Arial Black', 'Microsoft YaHei', 'PingFang SC', sans-serif";

      for (let i = 1; i <= this.cabinetMaxUbit; i++) {
        const uBaseY = height - i * uHeight;
        const y = uBaseY + uHeight / 2;


        // 每5个U位添加特殊标记行
        if (i % 5 === 0) {
          ctx.fillStyle = "rgba(30, 70, 90, 0.4)";
          ctx.fillRect(0, uBaseY, width, uHeight);
        }

        // 设置字体
        ctx.font = fontFamily;
        ctx.textBaseline = "middle";

        if (side === "left") {
          // 绘制左侧刻度线
          ctx.strokeStyle = "#ffffff";
          ctx.lineWidth = 3;
          ctx.beginPath();
          ctx.moveTo(20, y);
          ctx.lineTo(80, y);
          ctx.stroke();

          ctx.textAlign = "left";

          // 先画黑色粗描边，再画白色细描边，最后填充白色

          ctx.fillStyle = "#fff";
          ctx.fillText(`${i}`, 100, y);
        } else {
          // 绘制右侧刻度线
          ctx.strokeStyle = "#ffffff";
          ctx.lineWidth = 3;
          ctx.beginPath();
          ctx.moveTo(width - 20, y);
          ctx.lineTo(width - 80, y);
          ctx.stroke();

          ctx.textAlign = "right";

          ctx.fillStyle = "#fff";
          ctx.fillText(`${i}`, width - 100, y);
        }

        // 为每个U位添加分割线
        ctx.strokeStyle = "rgba(200, 200, 200, 0.2)";
        ctx.lineWidth = 1;
        ctx.beginPath();
        ctx.moveTo(0, uBaseY);
        ctx.lineTo(width, uBaseY);
        ctx.stroke();

        // 为每5个U位添加更明显的分割线
        if (i % 5 === 0) {
          ctx.strokeStyle = "rgba(0, 255, 255, 0.6)";
          ctx.lineWidth = 2;
          ctx.beginPath();
          ctx.moveTo(0, uBaseY);
          ctx.lineTo(width, uBaseY);
          ctx.stroke();
        }
      }

      // 添加顶部边框
      ctx.strokeStyle = "rgba(0, 255, 255, 0.6)";
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(0, 0);
      ctx.lineTo(width, 0);
      ctx.stroke();

      texture.update();
      texture.hasAlpha = false;
      texture.wrapU = BABYLON.Texture.CLAMP_ADDRESSMODE;
      texture.wrapV = BABYLON.Texture.CLAMP_ADDRESSMODE;

      return texture;
    },


    // 创建机柜
    async createCabinet(x, z, cabNmb) {
      // 计算机柜尺寸
      const dk = 30 // 底宽
      const dc = 40 // 底长

      // 计算机柜实际高度
      const unitHeight = 2 // 每U的高度单位
      const baseHeight = 3 // 底座高度
      const topHeight = 2 // 顶盖高度
      const cabHeight = this.cabinetMaxUbit * unitHeight // 机柜主体高度
      const totalCabHeight = cabHeight + 0.5 // 总高度

      console.log(`机柜设置: ${this.cabinetMaxUbit}U, 总高度: ${totalCabHeight}`)
      // 创建机柜组
      const cabinetGroup = new BABYLON.TransformNode("cabinetGroup", this.scene)
      cabinetGroup.position = new BABYLON.Vector3(x, 0, z)
      // 创建机柜底，左，右，顶面
      const cabBottom = BABYLON.MeshBuilder.CreateBox("cabBottom", {
        width: dk + 1,
        height: baseHeight,
        depth: dc
      }, this.scene)
      cabBottom.position.y = baseHeight / 2
      cabBottom.material = this.defaultServerMaterial
      cabBottom.parent = cabinetGroup
      const cabLeft = BABYLON.MeshBuilder.CreateBox("cabLeft", {
        width: 1,
        height: totalCabHeight,
        depth: dc
      }, this.scene)
      cabLeft.position.x = -dk / 2 + 0.1
      cabLeft.position.y = totalCabHeight / 2 + baseHeight
      cabLeft.material = this.defaultServerMaterial
      cabLeft.parent = cabinetGroup
      const cabRight = BABYLON.MeshBuilder.CreateBox("cabRight", {
        width: 1,
        height: totalCabHeight,
        depth: dc
      }, this.scene)
      cabRight.position.x = dk / 2 - 0.1
      cabRight.position.y = totalCabHeight / 2 + baseHeight
      cabRight.material = this.defaultServerMaterial
      cabRight.parent = cabinetGroup
      const cabTop = BABYLON.MeshBuilder.CreateBox("cabTop", {
        width: dk + 1,
        height: topHeight,
        depth: dc
      }, this.scene)
      cabTop.position.y = totalCabHeight + topHeight / 2 + baseHeight
      cabTop.material = this.defaultServerMaterial
      cabTop.parent = cabinetGroup
      //创建前左,前右,后左,后右U位刻度立柱
      const uLeftTexture = this.createUPositionTexture("left");
      const uRightTexture = this.createUPositionTexture("right");

      // 创建前左刻度立柱
      const uLeft = BABYLON.MeshBuilder.CreateBox("uLeft", {
        width: 2.5,
        height: cabHeight,
        depth: 0.1
      }, this.scene);
      uLeft.position.x = -dk / 2 + 2;
      uLeft.position.y = cabHeight / 2 + baseHeight;
      uLeft.position.z = -(dc / 2 - 0.5);

      // 创建前左刻度立柱材质
      const uLeftMaterial = new BABYLON.StandardMaterial("uLeftMaterial", this.scene);
      uLeftMaterial.diffuseTexture = uLeftTexture;
      uLeftMaterial.diffuseTexture.uScale = 1;
      // vScale设置是关键 - 根据实际机柜高度和U数量进行自适应调整
      uLeftMaterial.diffuseTexture.vScale = 1;
      uLeftMaterial.diffuseTexture.vOffset = 0;
      uLeft.material = uLeftMaterial;
      uLeft.parent = cabinetGroup;

      // 创建前右刻度立柱
      const uRight = BABYLON.MeshBuilder.CreateBox("uRight", {
        width: 2.5,
        height: cabHeight,
        depth: 0.1
      }, this.scene);
      uRight.position.x = dk / 2 - 2;
      uRight.position.y = cabHeight / 2 + baseHeight;
      uRight.position.z = -(dc / 2 - 0.5);

      // 创建前右刻度立柱材质
      const uRightMaterial = new BABYLON.StandardMaterial("uRightMaterial", this.scene);
      uRightMaterial.diffuseTexture = uRightTexture;
      uRightMaterial.diffuseTexture.uScale = 1;
      uRightMaterial.diffuseTexture.vScale = 1;
      uRightMaterial.diffuseTexture.vOffset = 0;
      uRight.material = uRightMaterial;
      uRight.parent = cabinetGroup;

      // 创建后左刻度立柱
      const uBackLeft = BABYLON.MeshBuilder.CreateBox("uBackLeft", {
        width: 2.5,
        height: cabHeight,
        depth: 0.1
      }, this.scene);
      uBackLeft.position.x = -dk / 2 + 2.5;
      uBackLeft.position.y = cabHeight / 2 + baseHeight;
      uBackLeft.position.z = dc / 2 - 0.5;

      // 创建后左刻度立柱材质
      const uBackLeftMaterial = new BABYLON.StandardMaterial("uBackLeftMaterial", this.scene);
      uBackLeftMaterial.diffuseTexture = this.createUPositionTexture("left");
      uBackLeftMaterial.diffuseTexture.uScale = 1;
      uBackLeftMaterial.diffuseTexture.vScale = 1;
      uBackLeftMaterial.diffuseTexture.vOffset = 0;
      uBackLeft.material = uBackLeftMaterial;
      uBackLeft.rotation.y = Math.PI; // 旋转180度，使纹理方向正确
      uBackLeft.parent = cabinetGroup;

      // 创建后右刻度立柱
      const uBackRight = BABYLON.MeshBuilder.CreateBox("uBackRight", {
        width: 2.5,
        height: cabHeight,
        depth: 0.1
      }, this.scene);
      uBackRight.position.x = dk / 2 - 2.5;
      uBackRight.position.y = cabHeight / 2 + baseHeight;
      uBackRight.position.z = dc / 2 - 0.5;

      // 创建后右刻度立柱材质
      const uBackRightMaterial = new BABYLON.StandardMaterial("uBackRightMaterial", this.scene);
      uBackRightMaterial.diffuseTexture = this.createUPositionTexture("right");
      uBackRightMaterial.diffuseTexture.uScale = 1;
      uBackRightMaterial.diffuseTexture.vScale = 1;
      uBackRightMaterial.diffuseTexture.vOffset = 0;
      uBackRight.material = uBackRightMaterial;
      uBackRight.rotation.y = Math.PI; // 旋转180度，使纹理方向正确
      const doorGroup = new BABYLON.TransformNode("doorGroup", this.scene)
      doorGroup.parent = cabinetGroup
      //创建机柜前门
      const doorTexture = this.createMeshDoorTexture()
      const door = BABYLON.MeshBuilder.CreateBox("door", {
        width: dk - 1,
        height: totalCabHeight,
        depth: 0.1
      }, this.scene)
      door.position.x = 0
      door.position.y = totalCabHeight / 2 + baseHeight
      door.position.z = -(dc / 2 - 0.05) // 前门位置稍微向前突出一点
      door.material = doorTexture// 根据机柜高度调整纹理缩放
      door.metadata = { type: "door" }
      door.parent = doorGroup
      // 创建机柜后左门
      const backDoorLeftGroup = new BABYLON.CreateBox("backDoorLeftGroup", {
        width: dk / 2,
        height: totalCabHeight,
        depth: 0.1
      }, this.scene)
      backDoorLeftGroup.position.x = dk / 4
      backDoorLeftGroup.position.y = totalCabHeight / 2 + baseHeight
      backDoorLeftGroup.position.z = dc / 2 - 0.05 // 后左门位置稍微向前突出一点
      backDoorLeftGroup.material = this.createMeshBackLeftDoorTexture();
      backDoorLeftGroup.metadata = { type: "door" }
      backDoorLeftGroup.parent = doorGroup
      // 创建机柜后右门
      const backDoorRightGroup = new BABYLON.CreateBox("backDoorRightGroup", {
        width: dk / 2,
        height: totalCabHeight,
        depth: 0.1
      }, this.scene)
      backDoorRightGroup.position.x = -dk / 4
      backDoorRightGroup.position.y = totalCabHeight / 2 + baseHeight
      backDoorRightGroup.position.z = dc / 2 - 0.05 // 后右门位置稍微向前突出一点
      backDoorRightGroup.material = this.createMeshBackDoorTexture();
      backDoorRightGroup.metadata = { type: "door" }
      //设置纹理位置稍微向下
      // backDoorRightGroup.rotation.y = Math.PI // 旋转180度，使纹理方向正确
      backDoorRightGroup.parent = doorGroup


      // 保存机柜部件
      this.cabinetMeshes = {
        cabinetGroup,
        doorGroup,
        backDoorLeftGroup,
        backDoorRightGroup,
        cabBottom,
        cabLeft,
        cabRight,
        cabTop,
        door,
      }

      // 将机柜添加到机柜列表
      this.rackList.push(cabinetGroup)
      this.rackList.push(doorGroup)
    },

    // 创建网格门纹理
    createMeshDoorTexture() {
      // /img/机柜门.webp
      const texture = new BABYLON.PBRMaterial("doorTexture", this.scene)
      texture.albedoTexture = new BABYLON.Texture("/img/机柜门.png", this.scene)
      texture.albedoTexture.hasAlpha = true // 确保纹理支持透明度
      texture.albedoTexture.uScale = 1
      texture.albedoTexture.vScale = 1
      texture.roughness = 0.1 // 设置粗糙度
      texture.metallic = 0.1 // 设置金属度
      return texture
    },
    //创建机柜后门
    createMeshBackDoorTexture() {
      // /img/机柜后门.webp
      const texture = new BABYLON.PBRMaterial("backDoorTexture", this.scene)
      texture.albedoTexture = new BABYLON.Texture("/img/rack_door_back.jpg", this.scene)
      texture.albedoTexture.hasAlpha = true // 确保纹理支持透明度
      texture.albedoTexture.uScale = 1
      texture.albedoTexture.vScale = 1
      texture.roughness = 0.1 // 设置粗糙度
      texture.metallic = 0.1 // 设置金属度
      return texture
    },

    createMeshBackLeftDoorTexture() {
      // /img/机柜后门.webp
      const texture = new BABYLON.PBRMaterial("backDoorTexture", this.scene)
      texture.albedoTexture = new BABYLON.Texture("/img/rack_front_door.jpg", this.scene)
      texture.albedoTexture.hasAlpha = true // 确保纹理支持透明度
      texture.albedoTexture.uScale = 1
      texture.albedoTexture.vScale = 1
      texture.roughness = 0.1 // 设置粗糙度
      texture.metallic = 0.1 // 设置金属度
      return texture
    },

    loadTexture(url) {
      return new Promise((resolve, reject) => {
        // 检查缓存
        if (this.textureCache[url]) {
          resolve(this.textureCache[url])
          return
        }

        const texture = new BABYLON.Texture(url, this.scene, false, true, BABYLON.Texture.BILINEAR_SAMPLINGMODE, () => {
          this.textureCache[url] = texture
          resolve(texture)
        }, (err) => {
          console.error('纹理加载失败:', url, err)
          resolve(null) // 加载失败时返回null，避免阻塞
        })

        // 配置纹理设置
        texture.hasAlpha = false
        texture.anisotropicFilteringLevel = 4
      })
    },

    // 批量渲染设备
    async renderDevices(devices) {
      if (!devices || devices.length === 0) return

      // 预加载纹理
      const texturePromises = []
      // listingType
      for (const device of devices) {
        const deviceImage = this.imgList?.find(img => img.devicesId === device.id)
        if (deviceImage) {
          if (deviceImage.urls) {
            for (const key of Object.keys(deviceImage.urls)) {
              texturePromises.push(this.loadTexture(deviceImage.urls[key]))
            }
          } else if (deviceImage.url) {
            texturePromises.push(this.loadTexture(deviceImage.url))
          }
        }
      }

      // 等待纹理加载
      await Promise.all(texturePromises)

      // 分批处理设备渲染
      const batchSize = 10
      const batches = Math.ceil(devices.length / batchSize)

      for (let i = 0; i < batches; i++) {
        const start = i * batchSize
        const end = Math.min(start + batchSize, devices.length)
        const batchDevices = devices.slice(start, end)

        // 批量创建服务器
        for (const device of batchDevices) {
          try {
            // 获取设备图片
            let deviceImgMap = { front: null, back: null, left: null, right: null, top: null, bottom: null }

            const deviceImage = this.imgList?.find(img => img.devicesId === device.id)
            if (deviceImage) {
              if (deviceImage.urls) {
                deviceImgMap = deviceImage.urls
              } else if (deviceImage.url) {
                const singleUrl = deviceImage.url
                deviceImgMap = {
                  front: singleUrl, back: singleUrl, left: singleUrl, right: singleUrl, top: singleUrl, bottom: singleUrl
                }
              }
            }

            // 计算服务器位置
            const unitHeight = 2 // 每U对应的高度单位
            const baseHeight = 3 // 机柜底座高度

            // 计算服务器位置
            const serverPosition = baseHeight + (device.startUbit - 1) * unitHeight

            // 创建服务器
            await this.createServer(serverPosition, device.ubit, deviceImgMap, device.id, device.listingType)

            // 修正服务器方向：让服务器正面朝向机柜前方（z轴正方向）
            const serverInfo = this.serverRegistry[device.id]
            if (serverInfo && serverInfo.group) {
              // 默认z轴正方向为前方，如果不是则旋转
              serverInfo.group.rotation.y = 0 // 保证正面朝向z轴正方向
            }
          } catch (err) {
            console.error('渲染设备失败:', err, device)
          }
        }

        // 允许渲染循环刷新UI
        await new Promise(resolve => setTimeout(resolve, 0))
      }
    },

    /**
     * 创建服务器
     * @param height  服务器高度
     * @param serverType  服务器类型，默认为2U
     * @param imgMap  服务器图片映射对象，包含front, back, left, right, top, bottom
     * @param id  服务器ID
     * @param listingType  服务器类型，0为前上架 1为后上架
     */
    async createServer(height, serverType = 2, imgMap, id, listingType = 0) {
      // 计算服务器高度
      const serverHeight = 2 * parseInt(serverType);

      // 创建服务器组 - 确保服务器高度和U位精确对应
      const serverGroup = new BABYLON.TransformNode("serverGroup_" + id, this.scene);
      serverGroup.position = new BABYLON.Vector3(0, height + serverHeight / 2, 2 - 0.2);
      serverGroup.metadata = { id: id, type: "server", uHeight: serverType };

      // 创建服务器主体
      const serverMain = BABYLON.MeshBuilder.CreateBox("serverMain_" + id, {
        width: 24,
        height: serverHeight - 0.2, // 略微减小高度，更精确地对准U位刻度
        depth: 36 - 0.2
      }, this.scene);
      serverMain.metadata = { id: id, type: "server", uHeight: serverType, listingType };
      // 让服务器主体和机柜U位对齐
      serverMain.position.z = -2;

      // 创建服务器材质
      const serverMaterial = await this.createServerMaterial(imgMap)
      serverMain.material = this.defaultServerMaterial
      serverMain.parent = serverGroup

      // 创建服务器面板
      const serverFace = BABYLON.MeshBuilder.CreateBox("server_" + id, {
        width: 26,
        height: serverHeight,
        depth: 0.2
      }, this.scene)

      // listingType: 0 前上架，1 后上架
      if (listingType === 1) {
        // 后上架，面板在后面
        serverFace.position.z = (36 / 2) - 2 // 后面板位置稍微向后突出一点
        // 旋转面板使其正面对外
        serverFace.rotation.y = Math.PI
      } else {
        // 前上架，面板在前面
        serverFace.position.z = -(36 / 2) - 2 // 前面板位置稍微向前突出一点
      }
      serverFace.metadata = { id: id, type: "server" }

      // 创建服务器面板材质
      const faceMaterial = await this.createServerFaceMaterial(imgMap)
      serverFace.material = faceMaterial
      serverFace.parent = serverGroup

      // 存储服务器引用
      this.serverRegistry[id] = {
        group: serverGroup,
        main: serverMain,
        face: serverFace
      }
    },

    // 创建服务器材质
    async createServerMaterial(imgMap) {
      // 创建材质键
      const materialKey = JSON.stringify(imgMap)

      // 检查缓存
      if (this.materialCache[materialKey + "_server"]) {
        return this.materialCache[materialKey + "_server"]
      }

      // 创建PBR材质
      const serverMaterial = new BABYLON.PBRMaterial("serverMaterial", this.scene)
      serverMaterial.metallic = 0.1
      serverMaterial.roughness = 0.9
      serverMaterial.microSurface = 0.5

      // 加载六面贴图
      let hasTextures = false

      if (imgMap) {
        // 尝试加载纹理
        const textures = {
          right: await this.loadTexture(imgMap.right),
          left: await this.loadTexture(imgMap.left),
          top: await this.loadTexture(imgMap.top),
          bottom: await this.loadTexture(imgMap.bottom),
          front: await this.loadTexture(imgMap.front),
          back: await this.loadTexture(imgMap.back)
        }

        // 检查是否至少有一个纹理加载成功
        hasTextures = Object.values(textures).some(texture => texture !== null)

        if (hasTextures) {
          // 创建六面纹理
          const frontBackMaterial = this.defaultServerMaterial.clone("frontBackMaterial")
          if (textures.front) frontBackMaterial.albedoTexture = textures.front

          const leftRightMaterial = this.defaultServerMaterial.clone("leftRightMaterial")
          if (textures.left) leftRightMaterial.albedoTexture = textures.left

          const topBottomMaterial = this.defaultServerMaterial.clone("topBottomMaterial")
          if (textures.top) topBottomMaterial.albedoTexture = textures.top

          // 创建多材质
          const multiMaterial = new BABYLON.MultiMaterial("serverMultiMaterial", this.scene)
          multiMaterial.subMaterials.push(leftRightMaterial) // right
          multiMaterial.subMaterials.push(leftRightMaterial) // left
          multiMaterial.subMaterials.push(topBottomMaterial) // top
          multiMaterial.subMaterials.push(topBottomMaterial) // bottom
          multiMaterial.subMaterials.push(frontBackMaterial) // front
          multiMaterial.subMaterials.push(frontBackMaterial) // back

          // 缓存并返回多材质
          this.materialCache[materialKey + "_server"] = multiMaterial
          return multiMaterial
        }
      }

      // 如果没有纹理，使用默认材质
      serverMaterial.albedoColor = new BABYLON.Color3(0.08, 0.08, 0.08)

      // 缓存并返回材质
      this.materialCache[materialKey + "_server"] = serverMaterial
      return serverMaterial
    },

    // 创建服务器面板材质
    async createServerFaceMaterial(imgMap) {
      // 创建材质键
      const materialKey = JSON.stringify(imgMap) + "_face"

      // 检查缓存
      if (this.materialCache[materialKey]) {
        return this.materialCache[materialKey]
      }

      // 创建面板材质
      const faceMaterial = new BABYLON.PBRMaterial("serverFaceMaterial", this.scene)
      faceMaterial.metallic = 0.1
      faceMaterial.roughness = 0.9

      // 尝试加载前面板纹理
      const frontTexture = imgMap && imgMap.front ? await this.loadTexture(imgMap.front) : null

      if (frontTexture) {
        faceMaterial.albedoTexture = frontTexture
      } else {
        // 如果没有纹理，使用默认颜色和花纹
        faceMaterial.albedoColor = new BABYLON.Color3(0.15, 0.15, 0.15)

        // 创建服务器面板花纹
        const facePatternTexture = this.createServerFacePattern()
        faceMaterial.bumpTexture = facePatternTexture
        faceMaterial.bumpTexture.level = 0.1
      }

      // 缓存并返回材质
      this.materialCache[materialKey] = faceMaterial
      return faceMaterial
    },

    // 创建服务器面板花纹
    createServerFacePattern() {
      const size = 256
      const texture = new BABYLON.DynamicTexture("serverFacePattern", size, this.scene, true)
      const ctx = texture.getContext()

      ctx.fillStyle = "#1a1a1a"
      ctx.fillRect(0, 0, size, size)

      // 绘制小型服务器面板通风孔和指示灯
      ctx.fillStyle = "#0f0f0f"

      // 通风条纹
      for (let y = 20; y < size - 20; y += 30) {
        for (let x = 10; x < size - 10; x += 2) {
          ctx.fillRect(x, y, 1, 12)
        }
      }

      // 螺丝孔
      ctx.fillStyle = "#2a2a2a"
      const screwPositions = [
        [15, 15], [size - 15, 15],
        [15, size - 15], [size - 15, size - 15]
      ]

      for (const [x, y] of screwPositions) {
        ctx.beginPath()
        ctx.arc(x, y, 4, 0, Math.PI * 2)
        ctx.fill()

        ctx.beginPath()
        ctx.arc(x, y, 2, 0, Math.PI * 2)
        ctx.fillStyle = "#0f0f0f"
        ctx.fill()
      }

      // 指示灯
      const lightPositions = [
        [size / 4, size - 30, "#00ff00"],
        [size / 4 + 20, size - 30, "#ff9900"],
        [size / 4 + 40, size - 30, "#0088ff"]
      ]

      for (const [x, y, color] of lightPositions) {
        ctx.beginPath()
        ctx.arc(x, y, 3, 0, Math.PI * 2)
        ctx.fillStyle = color
        ctx.fill()

        // 灯光光晕
        const gradient = ctx.createRadialGradient(x, y, 3, x, y, 8)
        gradient.addColorStop(0, color)
        gradient.addColorStop(1, "rgba(0,0,0,0)")
        ctx.fillStyle = gradient
        ctx.beginPath()
        ctx.arc(x, y, 8, 0, Math.PI * 2)
        ctx.fill()
      }

      texture.update()
      return texture
    },

    // 注册事件处理器
    registerEventHandlers() {
      // 鼠标悬停效果
      const onPointerMove = throttle((evt) => {
        const pick = this.scene.pick(evt.offsetX, evt.offsetY)

        // 清除所有高亮
        this.highlightLayer.removeAllMeshes()

        if (pick.hit && pick.pickedMesh) {
          const mesh = pick.pickedMesh

          if (mesh.metadata && mesh.metadata.type === "server") {
            // 高亮整个服务器组(包括主体和面板)
            const serverId = mesh.metadata.id || mesh.metadata.groupId;
            const serverInfo = this.serverRegistry[serverId];

            if (serverInfo) {
              this.highlightLayer.addMesh(serverInfo.main, BABYLON.Color3.FromHexString("#00FFFF"));
              this.highlightLayer.addMesh(serverInfo.face, BABYLON.Color3.FromHexString("#00FFFF"));
            } else {
              this.highlightLayer.addMesh(mesh, BABYLON.Color3.FromHexString("#00FFFF"));
            }
          } else if (mesh.metadata && mesh.metadata.type === "door") {
            // 高亮选中物体
            this.highlightLayer.addMesh(mesh, BABYLON.Color3.FromHexString("#00FFFF"));
          }
        }
      }, 100)

      // 点击处理
      const onClick = (evt) => {
        // 检查是否有任何一个时间线动画正在活动
        if (this.isAnyTimelineActive()) {
          this.$message({
            message: '动画执行中，请稍候...',
            type: 'warning',
            duration: 2000
          });
          return
        }

        const pick = this.scene.pick(evt.offsetX, evt.offsetY);

        if (pick.hit && pick.pickedMesh) {
          const mesh = pick.pickedMesh;
          if (mesh.metadata && mesh.metadata.type === "door") {
            // 根据是前门还是后门分别处理
            if (mesh === this.cabinetMeshes.door) {
              this.toggleFrontDoor();
            } else {
              this.toggleBackDoor();
            }
          } else if (mesh.metadata && mesh.metadata.type === "server") {
            const serverId = mesh.metadata.id || mesh.metadata.groupId;
            this.handleServerClick(serverId);
          }
        }
      }

      // 注册事件监听
      this.$refs.renderCanvas.addEventListener("pointermove", onPointerMove)
      this.$refs.renderCanvas.addEventListener("click", onClick)
    },

    // 检查是否有任何时间线动画正在活动
    isAnyTimelineActive() {
      return this.timelines.frontDoor.isActive() ||
        this.timelines.backDoor.isActive() ||
        this.timelines.server.isActive();
    },

    // 处理前门动画
    toggleFrontDoor() {
      let mesh = this.cabinetMeshes.door;

      // 初始化门的元数据
      if (!mesh.metadata) mesh.metadata = {};

      // 设置旋转轴点
      const boundingBox = mesh.getBoundingInfo().boundingBox;
      const pivot = new BABYLON.Vector3(
        mesh.position.x + mesh.scaling.x * boundingBox.extendSize.x,
        mesh.position.y - mesh.scaling.y * boundingBox.extendSize.y,
        mesh.position.z
      );
      mesh.setPivotPoint(pivot.subtract(mesh.position));

      // 清空前门时间线，准备新的动画
      this.timelines.frontDoor.clear();

      // 先收回所有服务器
      this.retractAllServers();

      if (!mesh.metadata.isOpen) {
        // 打开前门动画
        this.timelines.frontDoor.to(mesh.rotation, {
          y: mesh.rotation.y - Math.PI / 2,
          duration: 1,
          ease: "power2.out",
          onComplete: () => { mesh.metadata.isOpen = true; }
        });
      } else {
        // 关闭前门动画
        this.timelines.frontDoor.to(mesh.rotation, {
          y: mesh.rotation.y + Math.PI / 2,
          duration: 0.4,
          ease: "power2.in",
          onComplete: () => { mesh.metadata.isOpen = false; }
        });
      }
    },

    // 处理后门动画
    toggleBackDoor() {
      let backLeftMesh = this.cabinetMeshes.backDoorLeftGroup;
      let backRightMesh = this.cabinetMeshes.backDoorRightGroup;

      // 初始化门的元数据
      if (!backLeftMesh.metadata) backLeftMesh.metadata = {};
      if (!backRightMesh.metadata) backRightMesh.metadata = {};

      // 左后门
      const backLeftBoundingBox = backLeftMesh.getBoundingInfo().boundingBox;
      const backLeftPivot = new BABYLON.Vector3(
        backLeftMesh.position.x + backLeftMesh.scaling.x * backLeftBoundingBox.extendSize.x,
        backLeftMesh.position.y - backLeftMesh.scaling.y * backLeftBoundingBox.extendSize.y,
        backLeftMesh.position.z
      );
      backLeftMesh.setPivotPoint(backLeftPivot.subtract(backLeftMesh.position));

      // 右后门
      const backRightBoundingBox = backRightMesh.getBoundingInfo().boundingBox;
      const backRightPivot = new BABYLON.Vector3(
        backRightMesh.position.x - backRightMesh.scaling.x * backRightBoundingBox.extendSize.x,
        backRightMesh.position.y + backRightMesh.scaling.y * backRightBoundingBox.extendSize.y,
        backRightMesh.position.z
      );
      backRightMesh.setPivotPoint(backRightPivot.subtract(backRightMesh.position));

      // 清空后门时间线，准备新的动画
      this.timelines.backDoor.clear();

      // 先收回所有服务器
      this.retractAllServers();

      if (!backLeftMesh.metadata.isOpen) {
        // 打开后门动画
        this.timelines.backDoor
          .to(backLeftMesh.rotation, {
            y: backLeftMesh.rotation.y + Math.PI / 2,
            duration: 1,
            ease: "power2.out",
            onComplete: () => { backLeftMesh.metadata.isOpen = true; }
          })
          .to(backRightMesh.rotation, {
            y: backRightMesh.rotation.y - Math.PI / 2,
            duration: 1,
            ease: "power2.out",
            onComplete: () => { backRightMesh.metadata.isOpen = true; }
          }, "<"); // 同时执行
      } else {
        // 关闭后门动画
        this.timelines.backDoor
          .to(backLeftMesh.rotation, {
            y: backLeftMesh.rotation.y - Math.PI / 2,
            duration: 0.4,
            ease: "power2.in",
            onComplete: () => { backLeftMesh.metadata.isOpen = false; }
          })
          .to(backRightMesh.rotation, {
            y: backRightMesh.rotation.y + Math.PI / 2,
            duration: 0.4,
            ease: "power2.in",
            onComplete: () => { backRightMesh.metadata.isOpen = false; }
          }, "<"); // 同时执行
      }
    },

    // 处理服务器点击，确保动画执行期间不能重复触发
    handleServerClick(serverId) {
      // 检查是否有时间线动画正在执行
      if (this.isAnyTimelineActive()) {
        return;
      }
      console.log('点击服务器:', serverId, this.currentOpenServerId);
      // 如果点击的是当前已弹出的服务器，则收回
      if (this.currentOpenServerId === serverId) {
        this.retractAllServers();
      } else {
        // 先收回所有服务器
        this.retractServer(this.serverRegistry[this.currentOpenServerId]?.group);
        // 弹出点击的服务器
        const serverInfo = this.serverRegistry[serverId];
        if (serverInfo) {
          this.extendServer(serverInfo);
          this.currentOpenServerId = serverId;
        }
      }

      // 触发点击事件
      this.$emit('onClick', serverId);
    },

    // 根据服务器前后上架类型调整弹出方向
    extendServer(serverInfo) {
      if (!serverInfo || !serverInfo.group) return;

      // 清空服务器动画时间线
      this.timelines.server.clear();
      const serverGroup = serverInfo.group;
      const listingType = serverInfo.main.metadata.listingType;

      this.animating = true;

      // 根据前后上架类型决定弹出方向
      if (listingType === 1) {
        //判断后门是否打开
        if (this.cabinetMeshes.backDoorLeftGroup.metadata.isOpen || this.cabinetMeshes.backDoorRightGroup.metadata.isOpen) {
          // 后上架, 向后弹出
          this.timelines.server.to(serverGroup.position, {
            z: serverGroup.position.z + 20, // 正方向为向后
            duration: 0.3,
            ease: "power2.out",
            onComplete: () => { this.animating = false; }
          });
        } else {
          // 如果后门未打开，提示用户
          this.$message({
            message: '请先打开后门再操作',
            type: 'warning',
            duration: 2000
          });
          this.animating = false;
          return;
        }

      } else {
        // 判断前门是否打开
        if (this.cabinetMeshes.door.metadata.isOpen) {
          // 前上架，向前弹出
          this.timelines.server.to(serverGroup.position, {
            z: serverGroup.position.z - 20, // 负方向为向前
            duration: 0.3,
            ease: "power2.out",
            onComplete: () => { this.animating = false; }
          });
        } else {
          // 如果前门未打开，提示用户
          this.$message({
            message: '请先打开前门再操作',
            type: 'warning',
            duration: 2000
          });
          this.animating = false;
          return;
        }

      }
    },

    // 收回服务器
    retractServer(serverGroup) {
      if (!serverGroup) return;
      // 计算原始Z位置
      const originalZ = 2 - 0.2;
      // 创建动画
      gsap.to(serverGroup.position, {
        z: originalZ,
        duration: 0.3,
        ease: "power2.in",
        onStart: () => {
          this.animating = true;
        },
        onComplete: () => {
          this.animating = false;
        }
      });
    },

    // 收回所有服务器
    retractAllServers() {
      // 如果没有打开的服务器，不执行动画
      if (!this.currentOpenServerId) return;

      // 清空服务器动画时间线
      this.timelines.server.clear();

      // 遍历所有服务器
      let serversToAnimate = 0;
      const originalZ = 2 - 0.2;

      // 首先检查有多少服务器需要动画
      for (const id in this.serverRegistry) {
        const serverInfo = this.serverRegistry[id];
        if (Math.abs(serverInfo.group.position.z - originalZ) > 0.1) {
          serversToAnimate++;
        }
      }

      // 如果没有需要动画的服务器，直接返回
      if (serversToAnimate === 0) {
        return;
      }

      // 添加服务器收回动画
      for (const id in this.serverRegistry) {
        const serverInfo = this.serverRegistry[id];
        if (Math.abs(serverInfo.group.position.z - originalZ) > 0.1) {  // 只处理不在原位的服务器
          this.timelines.server.to(serverInfo.group.position, {
            z: originalZ,
            duration: 0.3,
            ease: "power2.in",
            onComplete: () => {
              serversToAnimate--;
              if (serversToAnimate <= 0) {
                this.currentOpenServerId = null;
                this.animating = false;
              }
            }
          }, "<"); // 同时执行
        }
      }
    },


    // 清理资源
    cleanup() {
      // 停止渲染循环
      this.engine.stopRenderLoop()

      // 释放材质
      for (const key in this.materialCache) {
        const material = this.materialCache[key]
        if (material instanceof BABYLON.MultiMaterial) {
          material.subMaterials.forEach(subMat => {
            if (subMat.albedoTexture) {
              subMat.albedoTexture.dispose()
            }
            subMat.dispose()
          })
        } else {
          if (material.albedoTexture) {
            material.albedoTexture.dispose()
          }
          material.dispose()
        }
      }

      // 释放纹理
      for (const key in this.textureCache) {
        this.textureCache[key].dispose()
      }

      // 处理高亮层
      if (this.highlightLayer) {
        this.highlightLayer.dispose()
      }

      // 释放场景
      if (this.scene) {
        this.scene.dispose()
      }

      // 释放引擎
      if (this.engine) {
        this.engine.dispose()
      }

      // 清空缓存
      this.materialCache = {}
      this.textureCache = {}
      this.serverRegistry = {}
    }
  },
  beforeDestroy() {
    // 清理所有资源
    this.cleanup()
  },
  computed: {
    isAnimating() {
      return this.animating
    }
  },
}
</script>

<style lang="scss" scoped>
.testCabinet {
  width: 100%;
  height: 100%;
  position: absolute;

  .renderCanvas {
    width: 100%;
    height: 100%;
    touch-action: none;
  }
}
</style>
